#lang rosetta-racket


(require data/queue)
(require racket/control)

(provide amb
         fail)


(define choices (make-queue))

(define (enqueue-choices! cs)
  (map (cλ enqueue! choices) cs))

(define (dequeue-choice!)
  (dequeue! choices))


(define-syntax (amb stx)
  (syntax-case stx ()
    ((ctx exp exps ...)
     #`(call/cc
        (λ (c)
          (enqueue-choices!
           (list
            #,@(map (λ (e) #`(λ () (c #,(datum->syntax #'ctx e)))) (syntax->datum #'(exps ...)))))
          exp)))))

(define (fail)
  (if (queue-empty? choices)
      (abort 'fail)
      ((dequeue-choice!))))

(define (foo)
  (amb 1 (foo)))